Ottimizzazione (informatica)
In informatica, l'ottimizzazione è il processo atto a modificare alcuni aspetti di un sistema per lavorare più efficientemente o per utilizzare meno risorse. Ad esempio, un programma per computer può essere ottimizzato in modo che venga eseguito più velocemente o in modo da richiedere meno memoria o consumare meno batteria. Il sistema può essere un singolo programma, un insieme di computer o un'intera rete come Internet. Anche se la parola "ottimizzazione" condivide la stessa base di "ottimo", è raro che il processo di ottimizzazione produca un sistema ottimo. Il sistema ottimizzato sarà tipicamente ottimo solamente in un senso. Uno può ridurre il tempo di esecuzione di un programma, ma al prezzo di consumare più memoria; oppure un programma può occupare meno memoria ma al prezzo della velocità di esecuzione. Non esiste una soluzione che "metta d'accordo tutti", cosicché il programmatore dovrà sapere quale strada perseguire. In più, il tentativo atto a rendere ottimo una parte del software è di solito più dispendioso rispetto ai benefici che si può ottenere. In questo modo il processo di ottimizzazione può essere saltato prima di trovare una soluzione completamente ottimale. Fortunatamente i più grandi miglioramenti arrivano sempre prima di questo processo. L'ottimizzazione può essere a più livelli. Al livello più alto il progetto può essere ottimizzato per sfruttare al meglio le risorse. L'implementazione può essere fatta mediante algoritmi efficienti e la scrittura di questi algoritmi beneficerà da quella di codice di buona qualità. L'uso di un compilatore con ottimizzatore aiuta a generare un programma eseguibile ottimizzato. Al livello più basso è possibile scrivere codice assembler a mano. Con i compilatori moderni e la crescente complessità dei processori, occorrono grandi abilità a scrivere codice assembler che è migliore di quello del compilatore. L'ottimizzazione di solito viene fatta in casi speciali e il codice può essere più difficile da leggere e può contenere più errori rispetto al codice non ottimizzato. Esempio I processi di calcolo possono essere scritti in diversi modi, con efficienze variabili. L'esempio seguente, un programma in C che somma tutti gli interi da 1 a N: int i, sum = 0; for (i = 1; i <= N; i++) sum += i; printf ("sum: %d\n", sum); Lo stesso codice può essere scritto così: int sum = (N * (N+1)) / 2; printf ("sum: %d\n", sum); L'ottimizzazione, spesso fatta automaticamente, è quella di prendere un metodo che è computazionalmente più efficiente mantenendo la stessa funzionalità. L'ottimizzazione non è sempre un processo ovvio e intuitivo. Nell'esempio precedente, la versione 'ottimizzata' potrebbe essere più lenta se N è sufficientemente basso e il processore è più veloce ad eseguire le addizioni e i cicli rispetto alle moltiplicazioni e alle divisioni. Compromessi L'ottimizzazione si concentra sul miglioramento di uno o più aspetti: tempo di esecuzione, utilizzo di memoria, banda, spazio del disco, consumo di energie ed altro. Questo provoca quel fenomeno detto compromesso (in inglese: tradeoff) — si ottimizza un aspetto alle spese degli altri. Ad esempio, aumentando la dimensione della cache migliorano le prestazioni in tempo di esecuzione, si aumenterà anche il consumo di memoria. Ci sono dei casi in cui il programmatore, effettuando l'ottimizzazione, deve decidere di rendere il software ottimo per alcune operazioni al prezzo di altre meno efficienti. Questi compromessi possono essere di natura non tecnica, come quando un concorrente pubblica un grafico di prestazioni che deve essere superato per ottenere successo commerciale, ma al prezzo di rendere l'uso del software meno efficiente. Questi cambiamenti sono detti di solito come pessimizzazioni (in inglese: pessimizations). Ambiti In ricerca operativa, l'ottimizzazione è il problema di determinare i valori d'ingresso di una funzione che minimizza o massimizza il suo valore. Di solito dei vincoli sono imposti sui valori che la funzione può ottenere; questo problema è noto come ottimizzazione dei vincoli. In informatica, l'ottimizzazione implica la modifica del codice e dei parametri di compilazione per produrre un software più efficiente. I problemi più comuni hanno di solito un grande numero di alternative che possono essere scelte dal programmatore. Colli di bottiglia L'ottimizzazione è seguita dalla ricerca di un collo di bottiglia: la parte critica del codice che è la prima consumatrice delle risorse. Di solito tale collo di bottiglia rappresenta il 20% del codice, ma è responsabile dell'80% dei risultati (vedere anche Principio di Pareto). Il Principio di Pareto (noto anche come regola 80-20) dichiara che per molti fenomeni l'80% delle conseguenze dipende dal 20% delle cause. Il progetto dell'architettura di un sistema influisce molto sulle prestazioni. La scelta di un algoritmo è più importante di ogni altro elemento del progetto. In alcuni casi, aggiungere più memoria può aiutare un programma a funzionare più velocemente. Ad esempio, un programma di filtro di solito legge ogni riga e filtra immediatamente l'output. Questo utilizza la memoria solo per una riga, ma le prestazioni sono tipicamente scarse. Queste possono essere migliorate leggendo l'intero file e scrivere poi il risultato, anche se ciò richiede più memoria. Quando ottimizzare? L'ottimizzazione può ridurre la leggibilità e aggiungere codice utilizzato solo per migliorare le prestazioni. Questo può complicare programmi e sistemi, rendendoli più difficili da leggere e per fare debug. Come risultato, l'ottimizzazione o l'aggiustamento delle prestazioni viene fatto di solito alla fine del processo dello sviluppo. Donald Knuth disse, parafrasando Hoarehttp://www.acm.org/ubiquity/views/v7i24_fallacy.html, * "Possiamo dimenticarci quelle piccole efficienze, per il 97% del tempo: l'ottimizzazione prematura è la radice di tutti i mali." (Knuth, Donald. Structured Programming with go to Statements, ACM Journal Computing Surveys, Vol 6, No. 4, Dec. 1974. p.268.) Charles Cook commentò, * "Sono d'accordo. Di solito non vale la pena di spendere un sacco di tempo a "micro-ottimizzare" codice prima di scoprire dove siano i colli di bottiglia. Ma quando si progetta software al livello di sistema, i problemi delle prestazioni devono essere sempre considerati sin dall'inizio. Un buon programmatore farà questo automaticamente, avendo l'esperienza sufficiente a scoprire i punti più critici. Un programmatore inesperto non si preoccuperà di questo, pensando che un po' di aggiustamento alla fine risolverà tutti i problemi." http://www.acm.org/ubiquity/views/v7i24_fallacy.html L'"ottimizzazione prematura" è una frase, utilizzata per descrivere la situazione di un programmatore che permette che le considerazioni sulle prestazioni possono influire sul progetto di un pezzo di codice. Questo può produrre un progetto che non è così chiaro come doveva essere o codice che non è corretto, perché il codice è diventato più complicato a causa dell'ottimizzazione. Un approccio alternativo è quello di progettare prima, fare codice dal progetto e quindi fare controlli di prestazioni sul codice per vedere se deve essere ottimizzato. Un progetto semplice ed elegante è più facile da ottimizzare in questa fase. In pratica, è bene tenere in mente gli obiettivi di prestazioni in mente quando si progetta il software, ma il programmatore bilancia gli obiettivi di progettazioni e dell'ottimizzazione. Linguaggi interpretati Nei linguaggi interpretati (specialmente quelli che vengono eseguiti ripetutamente come PHP e JavaScript) alcuni programmatori tolgono commenti, spazi e metodi o funzioni inutilizzati dai programmi prima di metterli in produzione. Se il programmatore toglie i commenti e la formattazione del codice, sacrifica la leggibilità del codice. Diventa più difficile per un umano leggere, fare il debug e di conseguenza modificare o estendere il codice. Aforismi * “La prima regola dell'ottimizzazione dei programmi è: non farlo. La seconda regola dell'ottimizzazione dei programmi (solo per esperti!) è: non farlo, ancora!” - Michael A. Jackson. * “L'ordine nel quale le operazioni vengono eseguite in ogni particolare caso è una questione molto interessante e curiosa, nella quale il nostro spazio non ci permette di comprendere completamente. In quasi ogni calcolo, è possibile effettuare una serie di aggiustamenti in ogni fase e varie considerazioni devono influenzare la scelta per gli scopi di un motore di calcolo. Un obiettivo essenziale è quello di scegliere quella combinazione che potrebbe ridurre al minimo il tempo necessario al calcolo.” - Note di Ada Byron sul motore analitico, 1842. * "In informatica, in nome dell'efficienza vengono commessi sempre più peccati (senza necessariamente ottenerla), piuttosto che per altri motivi, compresa la bieca stupidità.” - W.A. Wulf. * “Possiamo dimenticarci quelle piccole efficienze, per il 97% del tempo: l'ottimizzazione prematura è la radice di tutti i mali. Non dobbiamo sprecare il tempo nemmeno per quel 3% di codice critico.” - Knuth, parafrasando Hoare. * “I colli di bottiglia avvengono nei luoghi più incredibili. Quindi non provare ad inserire un trucco per velocizzare se non sai dov'è il collo di bottiglia.” - Rob Pike. Note Bibliografia * Jon Bentley: Writing Efficient Programs, ISBN 0-13-970251-2. * Donald Knuth: The Art of Computer Programming Voci correlate * Elenco di algoritmi di ottimizzazione * Ottimizzazione (motori di ricerca) * Direttiva (programmazione) * Opzioni di compilazione CFLAGS per il compilatore gcc (linguaggio C) Programmazione Categoria:Terminologia informatica